package com.tencent.sr.iris.activity.service.event.util;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.tencent.sr.iris.activity.common.enums.IrisErrorCode;
import com.tencent.sr.iris.activity.common.enums.TaskEstimateStatusEnum;
import com.tencent.sr.iris.activity.common.enums.UserPaymentTypeEnum;
import com.tencent.sr.iris.activity.common.enums.UserTaskStatusEnum;
import com.tencent.sr.iris.activity.common.exception.BizCommErrorCode;
import com.tencent.sr.iris.activity.common.util.AssertUtils;
import com.tencent.sr.iris.activity.common.util.SpelUtils;
import com.tencent.sr.iris.activity.common.util.TimeUtils;
import com.tencent.sr.iris.activity.dependency.dto.data.CommissionInfoDTO;
import com.tencent.sr.iris.activity.dependency.qufa.GroupTaskDependency;
import com.tencent.sr.iris.activity.dependency.user.UserCoreDependency;
import com.tencent.sr.iris.activity.dependency.user.UserLabelDependency;
import com.tencent.sr.iris.activity.domain.event.dto.ActivityDTO;
import com.tencent.sr.iris.activity.domain.event.dto.ActivityTaskDTO;
import com.tencent.sr.iris.activity.interfaces.dto.ActivityInfoDTO;
import com.tencent.sr.iris.activity.interfaces.dto.MultiTaskActivityDTO;
import com.tencent.sr.iris.activity.interfaces.enums.ActivityIdEnum;
import com.tencent.sr.iris.activity.interfaces.enums.ActivityRecordStatusEnum;
import com.tencent.sr.iris.activity.interfaces.enums.InviteGiftVersionEnum;
import com.tencent.sr.iris.activity.interfaces.enums.TaskEndStatusEnum;
import com.tencent.sr.iris.activity.interfaces.event.dto.ActivityEventDTO;
import com.tencent.sr.iris.activity.interfaces.request.task.UserRequest;
import com.tencent.sr.iris.activity.interfaces.response.group.task.FirstOrderInfoRes;
import com.tencent.sr.iris.activity.interfaces.response.group.task.UserPaymentResponse;
import com.tencent.sr.iris.activity.repository.entity.TIrisUserTaskRecordDO;
import com.tencent.sr.iris.activity.service.activity.IrisActivityTaskService;
import com.tencent.sr.iris.activity.service.config.ActivityConfig;
import com.tencent.sr.iris.activity.service.config.LocalCacheSwitchConfig;
import com.tencent.sr.iris.activity.service.config.ResponseMockConfig;
import com.tencent.sr.iris.activity.service.constant.ActivityRedisKey;
import com.tencent.sr.iris.activity.service.localcache.LocalCacheManager;
import com.tencent.sr.iris.user.core.service.interfaces.dto.tutor.UserTutorRelationDTO;
import com.tencent.sr.iris.user.core.service.interfaces.dto.user.UserWideDTO;
import com.tencent.sr.iris.user.core.service.interfaces.enums.LeaderTypeEnum;
import com.tencent.sr.iris.user.core.service.interfaces.enums.StaffFromTypeEnum;
import com.tencent.sr.iris.user.core.service.interfaces.request.user.IrisUserWideListQueryRequest;
import com.tencent.sr.iris.user.core.service.interfaces.response.activity.MemberTimeResponse;
import com.tencent.sr.iris.user.core.service.interfaces.response.activity.SpecialInviteResponse;
import com.tencent.sr.iris.user.core.service.interfaces.response.activity.UserLevelResponse;
import com.tencent.sr.iris.user.core.service.interfaces.response.user.IrisQueryUsersInTagsResponse;
import com.tencent.sr.iris.user.core.service.interfaces.response.user.UserInfoQueryResponse;
import com.tencent.sr.rmall.common.exception.retail.TRetailBizException;
import com.tencent.sr.rmall.common.exception.retail.TRetailErrorException;
import com.tencent.sr.rmall.springbootstarter.redis.RedisClient;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.YearMonth;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * 活动工具类
 */
@Slf4j
@Component
public class ActivityCommonUtilService {

    @Resource
    protected UserCoreDependency userCoreDependency;
    @Resource
    private LocalCacheSwitchConfig localCacheSwitchConfig;
    @Resource
    private ActivityConfig activityConfig;
    @Resource
    private ResponseMockConfig responseMockConfig;
    @Resource
    private GroupTaskDependency groupTaskDependency;
    @Resource
    private RedisClient redisClient;
    @Resource
    private UserLabelDependency userLabelDependency;

    @Resource
    private RedissonClient redissonClient;

    @Resource
    private IrisActivityTaskService irisActivityTaskService;

    /**
     * 校验是否在活动有效期内
     *
     * @return
     */
    public boolean checkActivityTime(ActivityDTO activity, Long eventTime) {
        Date changeTime = new Date(eventTime);
        //获取活动开始时间和结束时间
        Date startTime = activity.getStartTime();
        Date endTime = activity.getEndTime();
        if (Objects.nonNull(startTime)) {
            if (compareDate(startTime, changeTime) > 0) {
                return false;
            }
        }
        if (Objects.nonNull(endTime)) {
            if (compareDate(changeTime, endTime) > 0) {
                return false;
            }
        }
        return true;
    }


    /**
     * 校验成为见习会员时间是否是30天内
     *
     * @return
     */
    public boolean checkTraineeTime(ActivityEventDTO msg, Long becomeTraineeTime) {
        log.info("邀请有礼校验见习会员时间是否是30天内,uid:{}", msg.getUid());
        //判断是在活动开始时间后成为的见习会员
        if (becomeTraineeTime < activityConfig.getActRealUserStartTimestamp()) {
            log.info("邀请有礼校验见习会员时间不在活动开始时间后,uid:{}", msg.getUid());
            return false;
        }
        //获取佣金变化时间
        Long changeTime = msg.getEventTime();

        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date(becomeTraineeTime));
        cal.set(Calendar.HOUR_OF_DAY, 23);
        cal.set(Calendar.MINUTE, 59);
        cal.set(Calendar.SECOND, 59);
        cal.add(Calendar.DATE, 29);
        Date time = cal.getTime();
        if (time.getTime() >= changeTime) {
            return true;
        }
        return false;
    }

    public static int compareDate(Date date1, Date date2) {
        return date1.compareTo(date2);
    }

    /**
     * 校验用户的等级是否属于userLevels范围内
     *
     * @param uid
     * @param userLevels
     * @return
     */
    public boolean isUserLevelIn(String uid, List<String> userLevels) {
        if (StrUtil.isBlank(uid) || CollectionUtil.isEmpty(userLevels)) {
            return false;
        }
        String levelId = queryUserLevelIdUseCache(uid);
        if (levelId == null) {
            return false;
        }
        return userLevels.contains(levelId);
    }

    /**
     * 校验用户的等级是否属于userLevels范围内
     *
     * @param uid
     * @param userLevels
     * @return
     */
    public boolean isUserLevelInNoCache(String uid, List<String> userLevels) {
        if (StrUtil.isBlank(uid) || CollectionUtil.isEmpty(userLevels)) {
            return false;
        }
        String levelId = queryUserLevelId(uid);
        if (levelId == null) {
            return false;
        }
        return userLevels.contains(levelId);
    }

    /**
     * 查询用户等级
     *
     * @param uid
     * @return
     */
    public String queryUserLevelIdUseCache(String uid) {
        try {
            if (localCacheSwitchConfig.isQueryUserLevelON()) {
                return LocalCacheManager.LOCALCACHE_USER_LEVELID.get(uid, () -> Optional.ofNullable(queryUserLevelId(uid)))
                        .orElse(null);
            }
            return queryUserLevelId(uid);
        } catch (ExecutionException e) {
            log.error("queryUserLevelIdUseCache异常, uid:{}", uid, e);
        }
        return null;
    }

    /**
     * 查询用户等级
     *
     * @param uid
     * @return
     */
    public String queryUserLevelId(String uid) {
        //查询用户是否是特邀会员
        UserLevelResponse userLevelResponse = userCoreDependency
                .queryUserLevel(uid, null);
        if (Objects.isNull(userLevelResponse)) {
            log.info("查询用户会员等级为空,uid:{}", uid);
            throw new TRetailErrorException("查询用户会员等级为空,uid:" + uid);
        }
        String levelId = userLevelResponse.getLevelId();
        return levelId;
    }

    /**
     * 校验uid的类型是否在范围内
     *
     * @param uid
     * @param staffFromTypeEnumList
     * @return
     */
    public boolean isStaffFromTypeIn(String uid, List<StaffFromTypeEnum> staffFromTypeEnumList) {
        //查询用户类型
        UserInfoQueryResponse userInfoQueryResponse = userCoreDependency
                .queryUserInfo(uid, true);
        if (Objects.isNull(userInfoQueryResponse) || Objects.isNull(userInfoQueryResponse.getUserInfoDTO())) {
            log.info("查询uid为空,uid:{}", uid);
            return false;
        }
        return staffFromTypeEnumList.contains(
                StaffFromTypeEnum.getByCode(String.valueOf(userInfoQueryResponse.getUserInfoDTO().getType())));
    }

    /**
     * 校验是否是非特邀会员
     *
     * @return
     */
    public boolean checkSpecialInvite(String uid) {
        SpecialInviteResponse specialInviteResponse = querySpecialInvite(uid);
        String tag = specialInviteResponse.getTag();
        return !LeaderTypeEnum.SPECIAL_LEADER.getCode().equals(tag);
    }

    public SpecialInviteResponse querySpecialInviteCache(String uid) {
        if (StrUtil.isBlank(uid)) {
            return new SpecialInviteResponse();
        }

        if (localCacheSwitchConfig.isUserSpecialInviteON()) {
            try {
                Optional<SpecialInviteResponse> optional = LocalCacheManager.LOCALCACHE_USER_SPECIALINVITE.get(uid,
                        () -> Optional.ofNullable(querySpecialInvite(uid)));
                if (optional.isPresent()) {
                    return optional.get();
                }
                throw new TRetailErrorException("获取缓存特邀会员信息为空");
            } catch (ExecutionException e) {
                log.error("获取缓存特邀会员信息异常", e);
                throw new TRetailErrorException(e);
            }
        }

        return querySpecialInvite(uid);
    }

    public SpecialInviteResponse querySpecialInvite(String uid) {
        //查询用户是否是特邀会员
        log.info("查询是否是特邀会员,uid:{}", uid);
        SpecialInviteResponse specialInviteResponse = responseMockConfig.getSpecialInviteMock(uid);
        if (specialInviteResponse != null) {
            log.info("querySpecialInvite 命中mock数据白名单，直接返回mock数据，uid:{}，querySpecialInvite:{}", uid,
                    JSON.toJSONString(specialInviteResponse));
            return specialInviteResponse;
        }
        specialInviteResponse = userCoreDependency
                .querySpecialInvite(uid, true);
        log.info("查询是否是特邀会员,response:{}", JSON.toJSONString(specialInviteResponse));
        if (Objects.isNull(specialInviteResponse)) {
            log.info("查询是否是特邀会员接口返回为null,uid:{}", uid);
            throw new TRetailErrorException("查询是否是特邀会员接口返回为null");
        }
        return specialInviteResponse;
    }

    /**
     * 查询用户宽表
     *
     * @param uidList
     * @return
     */
    public Map<String, UserWideDTO> queryUserWideMapCache(List<String> uidList) {
        if (CollectionUtil.isEmpty(uidList)) {
            return Collections.emptyMap();
        }

        uidList = uidList.stream().filter(i -> StrUtil.isNotBlank(i))
                .distinct().collect(Collectors.toList());
        if (localCacheSwitchConfig.isBatchQueryUserListON()) {
            Map<String, UserWideDTO> caches = Maps.newHashMap(LocalCacheManager.LOCALCACHE_USER_WIDE_INFO.getAllPresent(uidList));

            List<String> modifiableUidList = Lists.newArrayList(uidList);
            modifiableUidList.removeAll(caches.keySet());
            List<UserWideDTO> userWideList = queryUserWideList(modifiableUidList);
            if (CollectionUtil.isNotEmpty(userWideList)) {
                Map<String, UserWideDTO> map = userWideList.stream().collect(
                        Collectors.toMap(UserWideDTO::getUid, i -> i, (i1, i2) -> i1));
                LocalCacheManager.LOCALCACHE_USER_WIDE_INFO.putAll(map);
                caches.putAll(map);
            }
            return caches;
        }

        List<UserWideDTO> userWideDTOS = queryUserWideList(uidList);
        return userWideDTOS.stream().collect(
                Collectors.toMap(UserWideDTO::getUid, i -> i, (i1, i2) -> i1));
    }

    /**
     * 查询用户信息列表
     *
     * @param uidList
     * @return
     */
    public List<UserWideDTO> queryUserWideList(List<String> uidList) {
        if (CollectionUtil.isEmpty(uidList)) {
            return Collections.emptyList();
        }

        IrisUserWideListQueryRequest request = new IrisUserWideListQueryRequest();
        request.setUidList(uidList);
        List<UserWideDTO> userWideDTOS = userCoreDependency.batchQueryUserList(request);
        return Optional.ofNullable(userWideDTOS)
                .orElse(Collections.emptyList());
    }

    /**
     * 查询升级场景值
     *
     * @param uid
     * @return
     */
    public IrisQueryUsersInTagsResponse queryUserTags(String uid) {
        IrisQueryUsersInTagsResponse userTags;
        try {
            if (localCacheSwitchConfig.isQueryUserTagsON()) {
                userTags = LocalCacheManager.USER_TAGS_CACHE.get(uid,
                        () -> Optional.ofNullable(userLabelDependency.queryUserTags(uid))).orElse(null);
                return userTags;
            }
            return userLabelDependency.queryUserTags(uid);
        } catch (ExecutionException e) {
            log.error("queryUserTags error, uid:{}", uid, e);
        }
        return null;
    }

    public Long queryUserMemberTimeStampUseCache(String uid, String userLevelId) {
        Long mockUserMemberTime = responseMockConfig.getMockUserMemberTime(uid);
        if (mockUserMemberTime != null) {
            log.info("queryUserMemberTimeStamp 命中mock数据白名单，直接返回mock数据，uid:{}，mockUserMemberTime:{}", uid,
                    mockUserMemberTime);
            return mockUserMemberTime;
        }
        MemberTimeResponse memberTimeResponse = null;
        try {
            if (localCacheSwitchConfig.isQueryUserMemberTimeON()) {
                memberTimeResponse = LocalCacheManager.LOCALCACHE_USER_MEMBER_TIME.get(
                        String.format("%s_%s", uid, userLevelId),
                        () -> userCoreDependency.queryUserMemberTime(uid, userLevelId));
                return memberTimeResponse.getTimeStamp();
            }
            memberTimeResponse = userCoreDependency.queryUserMemberTime(uid, userLevelId);
            return memberTimeResponse.getTimeStamp();
        } catch (ExecutionException e) {
            log.error("queryUserMemberTimeStamp error, uid:{},userLevelId:{}", uid, userLevelId, e);
        }
        return null;
    }

    /**
     * 查询是否是云选新用户
     *
     * @param uid
     * @return
     */
    public boolean isYunXuanNewUser(String uid) {
        if (activityConfig.getYunXuanUidWhiteList().contains(uid)) {
            log.info("命中测试云选新用户白名单，uid:{}", uid);
            return true;
        }

        String unionId = userCoreDependency.queryUnionIdByUid(uid);
        if (Strings.isNullOrEmpty(unionId)) {
            throw new TRetailBizException("unionId不能为空");
        }
        UserRequest request = new UserRequest();
        request.setUnionId(unionId);
        UserPaymentResponse response = groupTaskDependency.queryUserPaymentInfo(request);
        if (Objects.nonNull(response) && UserPaymentTypeEnum.NEW.getCode().equals(response.getUserType())) {
            return true;
        }
        return false;
    }

    /**
     * 查询缓存信息
     *
     * @param keys
     * @return
     */
    public <T> List<T> batchQueryCache(List<String> keys, int expireSeconds, Function<List<String>, List<T>> queryFunc,
                                       Function<T, String> keyFunc, Function<T, String> serializer, Function<String, T> deserializer) {
        if (CollectionUtil.isEmpty(keys)) {
            return Collections.emptyList();
        }

        int size = keys.size();
        Map<String, Integer> notExistMap = Maps.newHashMapWithExpectedSize(size);
        List<String> values = redisClient.mget(keys.toArray(new String[size]));
        for (int i = 0; i < size; i++) {
            String val = values.get(i);
            if (StrUtil.isBlank(val)) {
                notExistMap.put(keys.get(i), i);
            }
        }

        if (CollectionUtil.isEmpty(notExistMap)) {
            return values.stream().map(deserializer).filter(i -> i != null)
                    .collect(Collectors.toList());
        }
        //缓存过期，重新查询
        List<String> expireKeys = keys.stream()
                .filter(i -> notExistMap.keySet().contains(i)).collect(Collectors.toList());
        List<T> list = queryFunc.apply(expireKeys);
        if (CollectionUtil.isNotEmpty(list)) {
            List<String> k = Lists.newArrayList();
            List<String> v = Lists.newArrayList();
            for (T response : list) {
                if (response == null) {
                    continue;
                }
                String cacheKey = keyFunc.apply(response);
                //获取原索引，重新设置
                Integer idx = notExistMap.get(cacheKey);
                if (idx != null) {
                    values.set(idx, serializer.apply(response));
                }
                k.add(cacheKey);
                v.add(serializer.apply(response));
            }
            //随机缓存时间
            if (CollectionUtil.isNotEmpty(k) && CollectionUtil.isNotEmpty(v)) {
                int low = (int) (expireSeconds * 0.6);
                int expire = new Random().nextInt(expireSeconds - low) + low;
                v.add(String.valueOf(expire));
                batchSetEx(k, v);
            }
        }

        return values.stream().map(deserializer).filter(i -> i != null)
                .collect(Collectors.toList());
    }

    /**
     * 批量设置缓存和过期时间
     *
     * @param cacheKeys
     * @param cacheValues
     */
    public void batchSetEx(List<String> cacheKeys, List<String> cacheValues) {
        AssertUtils.isEqual(cacheKeys.size() + 1, cacheValues.size(), BizCommErrorCode.PARAM_ERROR);
        redisClient.eval(ActivityRedisKey.BATCH_EXPIRE_SET_SCRIPT, cacheKeys, cacheValues);
    }

    public UserTutorRelationDTO queryUserTutorCache(String uid) {
        if (localCacheSwitchConfig.isQueryUserTutorRelationON()) {
            try {
                return LocalCacheManager.ADVISOR_CACHE.get(uid, () -> userCoreDependency.queryUserTutorRelation(uid));
            } catch (ExecutionException e) {
                log.error("获取缓存导师信息异常", e);
                throw new TRetailErrorException(e);
            }
        }
        return userCoreDependency.queryUserTutorRelation(uid);
    }

    /**
     * 获取数据版本
     *
     * @param oldInviteData
     * @param startTime
     * @param endTime
     * @return
     */
    public InviteGiftVersionEnum getInviteGiftVersion(Boolean oldInviteData, Long startTime, Long endTime) {
        if (oldInviteData == null) {
            //兼容线上旧接口
            return null;
        }
        if (oldInviteData) {
            return InviteGiftVersionEnum.BEFORE_V0621;
        }

        boolean valid = startTime != null;
        AssertUtils.isTrue(valid, IrisErrorCode.NEW_INVITE_DATA_TIME_NULL);
        boolean V0621 =
                YearMonth.from(DateUtil.date(startTime).toInstant().atZone(ZoneId.systemDefault()).toLocalDate())
                        .compareTo(YearMonth.from(DateUtil.date(InviteGiftVersionEnum.V0621.getStartTime())
                                .toInstant().atZone(ZoneId.systemDefault()).toLocalDate())) == 0;
        if (V0621) {
            return InviteGiftVersionEnum.V0621;
        }

        return InviteGiftVersionEnum.V0706;
    }

    /**
     * 查询不符合条件则等待重查，还不符合则抛异常
     *
     * @param query
     * @param retry
     * @param errorMsg
     * @param <T>
     * @return
     */
    public <T> T waitAndRetry(Supplier<T> query, Function<T, Boolean> retry, String errorMsg) {
        T t = query.get();
        if (retry.apply(t)) {
            //升级事件，查询不到标签值等待一段时间再查，如果还查不到则等待重试
            long queryWaitTime = activityConfig.getQueryWaitTime();
            try {
                log.warn("查询等待{}毫秒，errorMsg：{}", queryWaitTime, errorMsg);
                Thread.sleep(queryWaitTime);
            } catch (Exception e) {
                log.error("查询等待异常，errorMsg：{}", errorMsg, e);
            }
            t = query.get();
            if (retry.apply(t)) {
                log.error("等待{}毫秒后仍查询失败，errorMsg：{}", queryWaitTime, errorMsg);
                throw new TRetailErrorException(errorMsg);
            }
        }
        return t;
    }

    /**
     * 查询新上级准入开关
     *
     * @param uid
     * @return
     */
    public boolean getUseNewPidLevel(String uid) {
        if (!activityConfig.getTestUidWhiteList().contains(uid)) {
            return activityConfig.isUseNewPidLevel();
        }
        return responseMockConfig.isUseNewPidLevel();
    }


    /**
     * 注册有礼结束时间
     *
     * @param uid
     * @return
     */
    public long getRegistGiftEndTime(String uid) {
        if (activityConfig.getTestUidWhiteList().contains(uid)) {
            String registGiftEndTime = responseMockConfig.getRegistGiftEndTime();
            return TimeUtils.parse(registGiftEndTime).getTime();
        }
        return activityConfig.getRegistGiftEndTimeTimestamp();
    }

    /**
     * 获取特邀结束时间：优先取白名单配置的
     *
     * @param uid uid
     * @return 结束时间
     */
    public long getSpecialInviteEndTimeTimestamp(String uid) {
        if (activityConfig.getTestUidWhiteList().contains(uid)) {
            String specialInviteEndTime = responseMockConfig.getSpecialInviteEndTime();
            return Objects.requireNonNull(TimeUtils.parse(specialInviteEndTime)).getTime();
        }
        return activityConfig.getSpecialInviteEndTimeTimestamp();
    }

    /**
     * 处理活动状态
     *
     * @param taskRecords
     * @param commissionTaskPlusDay
     * @return
     */
    public ActivityInfoDTO handleActivityStatus(List<TIrisUserTaskRecordDO> taskRecords, int commissionTaskPlusDay) {
        int totalStage = taskRecords.size();
        TIrisUserTaskRecordDO last = taskRecords.get(totalStage - 1);

        ActivityInfoDTO activityRecord = new ActivityInfoDTO();

        TIrisUserTaskRecordDO eFinishedStage = taskRecords.stream()
                .filter(i -> Objects.equals(TaskEstimateStatusEnum.FINISHED.getCode(), i.getEstimateUserTaskStatus()))
                .max(Comparator.comparing(TIrisUserTaskRecordDO::getTier)).orElse(null);
        Integer eStage = Optional.ofNullable(eFinishedStage).map(TIrisUserTaskRecordDO::getTier).orElse(0);

        TIrisUserTaskRecordDO finishedStage = taskRecords.stream()
                .filter(i -> Objects.equals(UserTaskStatusEnum.FINISHED.getCode(), i.getUserTaskStatus()))
                .max(Comparator.comparing(TIrisUserTaskRecordDO::getTier)).orElse(null);
        Integer fStage = Optional.ofNullable(finishedStage).map(TIrisUserTaskRecordDO::getTier).orElse(0);

        int maxStage = taskRecords.stream().max(Comparator.comparing(TIrisUserTaskRecordDO::getTier))
                .map(TIrisUserTaskRecordDO::getTier).orElse(0);
        Integer minStage = taskRecords.stream().min(Comparator.comparing(TIrisUserTaskRecordDO::getTier))
                .map(TIrisUserTaskRecordDO::getTier).orElse(0);
        boolean extend = maxStage != totalStage;
        //部分继承的数据
        if (extend) {
            fStage = Math.max(fStage, minStage - 1);
            eStage = Math.max(eStage, minStage - 1);
        }

        //e<f：不存在（最大预估完成阶数不应小于最大实际完成阶数）
        TaskEndStatusEnum taskEndTimeStatus = TaskEndStatusEnum.getCodeByTaskEndTime(
                DateUtil.date(last.getCurrentTaskEndTime()), commissionTaskPlusDay);
        switch (taskEndTimeStatus) {
            case PROGRESS:
                //e=f=最高：最高阶预估已完成且实际已完成，展示“已完成”
                if (eStage == fStage && eStage == maxStage) {
                    return activityRecord.setCurrentTier(maxStage)
                            .setActivityStatus(ActivityRecordStatusEnum.FINISHED);
                }

                Integer finalFStage = fStage;
                Integer progressingStage = taskRecords.stream().filter(i -> i.getTier() != null && i.getTier() > finalFStage)
                        .findFirst().map(TIrisUserTaskRecordDO::getTier).orElse(fStage + 1);
                //e≥f：（审核中：e阶，不展示）展示“进行中 （大于f的下一阶）”
                return activityRecord.setCurrentTier(progressingStage)
                        .setActivityStatus(ActivityRecordStatusEnum.PROGRESS);
            case PRE_END:
                //e=f=0：展示“未完成”
                if (eStage == fStage && eStage == 0) {
                    return activityRecord.setCurrentTier(0)
                            .setActivityStatus(ActivityRecordStatusEnum.UNFINISHED);
                }
                //e=f≠0：展示“已完成f阶”
                if (eStage == fStage && eStage != 0) {
                    //继承终态需判断阶数是上级还是下级
                    if (fStage < minStage) {
                        //已完成阶数为老上级，新上级无已完成
                        return activityRecord.setCurrentTier(0)
                                .setActivityStatus(ActivityRecordStatusEnum.UNFINISHED);
                    }

                    return activityRecord.setCurrentTier(fStage)
                            .setActivityStatus(ActivityRecordStatusEnum.FINISHED);
                }
                //e>f：展示“审核中e阶”
                return activityRecord.setCurrentTier(eStage)
                        .setActivityStatus(ActivityRecordStatusEnum.AUDITING);
            case END:
                //f=0：展示“未完成”
                if (fStage == 0) {
                    return activityRecord.setCurrentTier(0)
                            .setActivityStatus(ActivityRecordStatusEnum.UNFINISHED);
                }

                //继承终态需判断阶数是上级还是下级
                if (fStage < minStage) {
                    //已完成阶数为老上级，新上级无已完成
                    return activityRecord.setCurrentTier(0)
                            .setActivityStatus(ActivityRecordStatusEnum.UNFINISHED);
                }

                //e≥f：展示“已完成f阶”
                return activityRecord.setCurrentTier(fStage)
                        .setActivityStatus(ActivityRecordStatusEnum.FINISHED);
            default:
                break;
        }
        return activityRecord;
    }

    /**
     * 分组
     *
     * @param responses
     * @return
     */
    public Map<String, Map<String, List<TIrisUserTaskRecordDO>>> groupBy(List<TIrisUserTaskRecordDO> responses, Map<String, MultiTaskActivityDTO> multiTaskActivityConfig) {

        return responses.stream()
                //下级uid分组
                .collect(Collectors.groupingBy(TIrisUserTaskRecordDO::getUid,
                        //根据活动id，任务id，任务周期 分组
                        Collectors.groupingBy(i -> {
                                    MultiTaskActivityDTO multiTaskActivityDTO = multiTaskActivityConfig.get(i.getActivityType());
                                    String groupByExpression = Optional.ofNullable(multiTaskActivityDTO)
                                            .map(MultiTaskActivityDTO::getGroupByExpression).orElse(null);
                                    if (StrUtil.isNotBlank(groupByExpression)) {
                                        return SpelUtils.parse(groupByExpression, i, String.class);
                                    }
                                    if (Objects.equals(i.getActivityId(), ActivityIdEnum.REGIST_GIFT.getCode())) {
                                        return i.getUid();
                                    }
                                    return i.getBizId();
                                },
                                Collectors.collectingAndThen(Collectors.toList(),
                                        l -> l.stream().sorted(Comparator.comparing(TIrisUserTaskRecordDO::getTier))
                                                .collect(Collectors.toList())
                                )
                        )));
    }

    /**
     * 获取扩展信息
     *
     * @param extInfo
     * @return
     */
    public String buildTaskRecordExtInfo(String extInfo, CommissionInfoDTO commissionInfoDTO) {
        JSONObject extInfoJson;
        try {
            extInfoJson = Optional.ofNullable(JSON.parseObject(extInfo))
                    .orElseGet(JSONObject::new);
        } catch (Exception e) {
            log.info("buildTaskRecordExtInfo转换任务记录扩展信息失败", e);
            extInfoJson = new JSONObject();
        }

        //万人团佣金
        JSONObject commissionJson = Optional.ofNullable(extInfoJson.getJSONObject("commission"))
                .orElseGet(JSONObject::new);
        commissionJson.put("rewardIncomeAmt", commissionInfoDTO.getRewardIncomeAmt());
        commissionJson.put("actualSalesRewardIncomeAmtAll", commissionInfoDTO.getActualSalesRewardIncomeAmtAll());

        //首单信息
        FirstOrderInfoRes firstOrderInfo = commissionInfoDTO.getFirstOrderInfo();
        if (firstOrderInfo != null) {
            JSONObject firstOrder = new JSONObject();
            firstOrder.put("plainOrderId", firstOrderInfo.getPlainOrderId());
            firstOrder.put("orderStatus", firstOrderInfo.getOrderStatus());
            firstOrder.put("paymentAmount", firstOrderInfo.getPaymentAmount());
            firstOrder.put("couponPrice", firstOrderInfo.getCouponPrice());
            firstOrder.put("finishTime", firstOrderInfo.getFinishTime());
            extInfoJson.put("firstOrder", firstOrder);
        } else {
            extInfoJson.put("firstOrder", null);
        }

        return extInfoJson.toJSONString();
    }

    /**
     * 解析扩展字段
     *
     * @param extInfo
     * @param field
     * @return
     */
    public JSONObject parseExtInfoField(String extInfo, String field) {
        JSONObject extInfoJson;
        try {
            extInfoJson = Optional.ofNullable(JSON.parseObject(extInfo))
                    .orElseGet(JSONObject::new);
        } catch (Exception e) {
            log.info("parseExtInfoField转换任务记录扩展信息失败", e);
            extInfoJson = new JSONObject();
        }

        return extInfoJson.getJSONObject(field);
    }

    public boolean firstOrderAward(String uid, Date date) {
        try {
            String changeDate = activityConfig.getTestUidWhiteList().contains(uid)
                    ? responseMockConfig.getFirstOrderAwardChangeDate() : activityConfig.getFirstOrderAwardChangeDate();
            DateTime dateTime = DateUtil.parseDateTime(changeDate);
            if (DateUtil.compare(date, dateTime) > 0) {
                return true;
            }
        } catch (Exception e) {
            log.error("对比首单发奖切换时间失败：", e);
        }
        return false;
    }

    /**
     * 加锁
     *
     * @param pid
     * @param uid
     * @return
     * @throws InterruptedException
     */
    public RLock inviteGiftTryLock(String activityId, String pid, String uid) throws InterruptedException {
        if (!Objects.equals(activityId, ActivityIdEnum.INVITE_GIFT.getCode())) {
            return null;
        }
        RLock lock;
        String lockKey = ActivityRedisKey.getInviteTaskNewLockKey(pid);
        lock = redissonClient.getLock(lockKey);
        if (!lock.tryLock(30, TimeUnit.SECONDS)) {
            log.info("邀请有礼活动事件重试处理：获取分布式锁失败，当前上级邀请任务正在处理,pid:{},uid:{}", pid, uid);
            //抛个异常重试
            throw new TRetailErrorException("邀请有礼活动事件重试处理获取分布式锁失败");
        }
        return lock;
    }

    /**
     * 处理发奖信息
     *
     * @param userTaskRecordDO
     * @return
     */
    public Integer handleTaskAwardValue(TIrisUserTaskRecordDO userTaskRecordDO) {
        String uid = userTaskRecordDO.getUid();
        String taskBizId = userTaskRecordDO.getTaskId();
        String extInfo = userTaskRecordDO.getExtInfo();
        Date currentTaskStartTime = userTaskRecordDO.getCurrentTaskStartTime();
        String activityId = userTaskRecordDO.getActivityId();

        ActivityTaskDTO taskDTO = irisActivityTaskService.getTaskByTaskBizId(taskBizId);
        String awardInfo = taskDTO.getAwardInfo();
        JSONObject awardInfoJson = Optional.ofNullable(JSONObject.parseObject(awardInfo)).orElseGet(JSONObject::new);

        boolean firstOrderAward = firstOrderAward(uid, currentTaskStartTime);
        if (firstOrderAward && Objects.equals(activityId, ActivityIdEnum.INVITE_GIFT.getCode())) {
            JSONObject newAward = Optional.ofNullable(awardInfoJson.getJSONObject("newAward")).orElseGet(JSONObject::new);
            Integer value = newAward.getInteger("value");
            //发奖份数
            JSONObject firstOrder = Optional.ofNullable(parseExtInfoField(extInfo, "firstOrder"))
                    .orElseGet(JSONObject::new);
            Integer couponPrice = Optional.ofNullable(firstOrder.getInteger("couponPrice")).orElse(0);
            Integer paymentAmount = Optional.ofNullable(firstOrder.getInteger("paymentAmount")).orElse(0);
            int payValue = Math.max(0, paymentAmount - couponPrice);
            int actualSendValue = Math.min(payValue, value);
            userTaskRecordDO.setSendAward(actualSendValue);
            return actualSendValue;
        }

        Integer value = Optional.ofNullable(awardInfoJson.getInteger("value")).orElse(0);
        userTaskRecordDO.setSendAward(value);
        return value;
    }
}
